package kik.client.whiteboard;

import gwt.canvas.client.Canvas;
import kik.client.whiteboard.Graphics.Tools;
import gwt.g2d.client.graphics.ImageLoader;
import com.google.gwt.dom.client.ImageElement;
import java.util.ArrayList;
import java.util.Vector;

import kik.client.Conference;
import kik.client.common.ConferenceObject;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.DisclosurePanelImages;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.DialogBox;



@SuppressWarnings("deprecation")
/**
 * Klasa definująca tworzenie tablicy.
 * Definiuje ona wygląd graficzny tablicy oraz zajmuje się obsługę zdarzeń wykonanych na tablicy.
 */
public class Whiteboard extends ConferenceObject {
	private ArrayList<Graphics> graphics;
	public Graphics myGraphics;
	private Canvas canva = new Canvas();
	private DisclosurePanel whiteboardPanel;
	private Tools type;
	private int lastx=0;
	private int lasty=0;
	private int relx=0;
	private int rely=0;
	private int moved=0;
	private boolean captured = false;
	private TextBox input_text = new TextBox();
	private TextBox input_text2 = new TextBox();
	private HorizontalPanel input = new HorizontalPanel();
	private HorizontalPanel input2 = new HorizontalPanel();
	private DialogBox textInputBox = new DialogBox(true,true);
	private DialogBox loadImageBox = new DialogBox(true, true);
	private String text = new String();
	private int sx,sy;
	private Vector<Integer> xs;
	private Vector<Integer> ys;
	private int objID = 0;
	Button in_button;
	Button load_image_button;
	//private int sendDelay = 0;
	private boolean locked = false;
	
	/**
	 * Konstruktor tworzący tablice.
	 * 
	 * Tworzy elementy graficzne oraz układa je w odpowiedniej hierarchii.
	 * Definuje także obsługe zdarzeń myszy wykonanych na elementach graficznych.
	 * @param conf	Obiekt konferencji {@link Conference}
	 */
	public Whiteboard(Conference conf) {
		this.conf = conf;
		in_button = new Button("Drukuj",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						text = input_text.getText();
						input_text.setText("");
						textInputBox.hide();
						addGraphic(new Text(sx, sy, text, canva,owner,nextID()));
						redraw();
						text = "";
					}
		      	});
		input_text.addKeyDownHandler(new KeyDownHandler() {

			public void onKeyDown(KeyDownEvent event) {
				if(event.getNativeKeyCode() == '\n' || event.getNativeKeyCode() == '\r') {
					in_button.click();
				}
			}
			
		});
		input.add(input_text);
		input.add(in_button);
		textInputBox.setText("Co chcesz napisac ?");
		textInputBox.setAnimationEnabled(true);
		textInputBox.setWidget(input);
		load_image_button = new Button("Otworz",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						text = input_text2.getText();
						input_text2.setText("");
						loadImageBox.hide();
						final Vector<String> list = new Vector<String> ();
						list.add(text);
						ImageLoader.loadImages(list, new ImageLoader.CallBack() {
	                        public void onImagesLoaded(ImageElement[] imageElements) {
	                                ImageElement image = imageElements[0];
	                                if(image != null) {
	                                	Image g = new Image(image,sx,sy,canva,owner,nextID(),list.firstElement());
	                                	g.setCreate(true);
	                                	addGraphic(g);
	                                	canva.drawImage(image, sx, sy);
	                                }
	                        }
						});
						redraw();
						text = "";
					}
		      	});
		input_text2.addKeyDownHandler(new KeyDownHandler() {

			public void onKeyDown(KeyDownEvent event) {
				if(event.getNativeKeyCode() == '\n' || event.getNativeKeyCode() == '\r') {
					load_image_button.click();
				}
			}
			
		});
		input2.add(input_text2);
		input2.add(load_image_button);
		loadImageBox.setText("Podaj sciezke obrazka?");
		loadImageBox.setAnimationEnabled(true);
		loadImageBox.setWidget(input2);
		graphics = new ArrayList<Graphics>();
		whiteboardPanel = new DisclosurePanel(
				(DisclosurePanelImages)GWT.create(DisclosurePanelImages.class),"",true);
		VerticalPanel tmp = new VerticalPanel();
		canva.setSize("500px","450px");
		tmp.add(canva);
		Button b1 = new Button("[]",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.RECTANGLE;
					}
		      	});
		Button b2 = new Button("O",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.CIRCLE;
					}
		      	});
		Button b3 = new Button("-",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.LINE;
					}
		      	});
		Button b4 = new Button("+",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.MOVE;
					}
		      	});
		Button b5 = new Button("~",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.BRUSH;
					}
		      	});
		Button b6 = new Button("txt",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.TEXT;
					}
		      	});
		Button b7 = new Button("/\\",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.UP;
					}
		      	});
		Button b8 = new Button("\\/",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.DOWN;
					}
		      	});
		Button b9 = new Button("d",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.DEL;
					}
		      	});
		Button b10 = new Button("img",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						type = Tools.IMG;
					}
		      	});
		Button b11 = new Button("c",
				new ClickHandler() {
					public void onClick(ClickEvent event) {
						if(Window.confirm("Do you really wanna clear this shit?")){
							type = Tools.CLR;
							if(graphics.size()>0) {
								sendChange(graphics.get(0),Tools.CLR.toString());
							}
							graphics.clear();
							redraw();
						}
					}
		      	});
		HorizontalPanel tmp2 = new HorizontalPanel();
		tmp2.add(b1);
		tmp2.add(b2);
		tmp2.add(b3);
		tmp2.add(b4);
		tmp2.add(b5);
		tmp2.add(b6);
		tmp2.add(b7);
		tmp2.add(b8);
		tmp2.add(b9);
		tmp2.add(b10);
		tmp2.add(b11);
		tmp.add(tmp2);
		whiteboardPanel.add(tmp);
		canva.setBackgroundColor("#FFFFFF");
		canva.addMouseListener(new MouseListener() {
									int nx=0,ny=0;
									double radius = 0.0;
									boolean down = false;
									public void onMouseDown(Widget sender, int x, int y) {
										if(!down) {
											sx = x;
											sy = y;
											down = true;
											if(type == Tools.BRUSH) {
												canva.moveTo(x, y);
												canva.beginPath();
											}
											if(type == Tools.TEXT) {
												textInputBox.show();
												textInputBox.center();
												input_text.setFocus(true);
												down = false;
											}
											if(type == Tools.IMG) {
												loadImageBox.show();
												loadImageBox.center();
												input_text2.setFocus(true);
												down = false;
											}
										}
									}

									public void onMouseEnter(Widget sender) {
									}

									public void onMouseLeave(Widget sender) {
									}

									public void onMouseMove(Widget sender, int x, int y) {
										relx = x - lastx;
										rely = y - lasty;
										Graphics g = null;
										if(down) {
											if(type == Tools.RECTANGLE) {
												redraw();
												nx = x-sx;
												ny = y-sy;
												g = new Rectangle(sx,sy,nx,ny,canva,owner,nextID());
												g.draw();
											}
											else if(type == Tools.CIRCLE) {
												redraw();
												radius = Math.sqrt((sx-x)*(sx-x)+(sy-y)*(sy-y));
												g = new Circle(sx,sy,radius,canva,owner,nextID());
												g.draw();
											}
											else if(type == Tools.LINE) {
												redraw();
												g = new Line(sx,sy,x,y,canva,owner,nextID());
												g.draw();
											}
											else if(type == Tools.MOVE) {
												if(!captured) {
													int s = graphics.size();
													for(int i = s-1; i>=0;--i) {
														if(graphics.get(i).belongsTo(x,y)) {
															captured = true;
															moved = i;
															sendChange(new Locked(graphics.get(i).getOwner(),graphics.get(i).getID()),Tools.LOCK.toString());
															locked = true;
															break;
														}
													}
												}
												else {
													if(!graphics.get(moved).isLocked()){
														redraw();
														graphics.get(moved).modifyCords(relx, rely);
														g = graphics.get(moved);
													}
													else {
														if(!locked){
															moved = 0;
															captured = false;
															locked = false;
															relx = 0;
															rely = 0;
															redraw();
														}
													}
												}
											}	
											else if(type == Tools.BRUSH) {
												if(down) {
													canva.lineTo(x, y);
													if(!captured) {
														captured = true;
														xs = new Vector<Integer> ();
														ys = new Vector<Integer> ();
														xs.add(x);
														ys.add(y);
													}
													else {
														xs.add(x);
														ys.add(y);
														canva.setStrokeStyle("#000000");
														canva.beginPath();
														canva.moveTo(lastx,lasty);
														canva.lineTo(x,y);
														canva.closePath();
														canva.stroke();
													}
													canva.closePath();
												}
											}
										}
										else {
										}
										lastx = x;
										lasty = y;
										
									}

									public void onMouseUp(Widget sender, int x, int y) {
										relx = x - lastx;
										rely = y - lasty;
										if(type == Tools.RECTANGLE) {
											addGraphic(new Rectangle(sx,sy,nx,ny,canva,owner,nextID()));
										}
										if(type == Tools.CIRCLE) {
											addGraphic(new Circle(sx,sy,radius,canva,owner,nextID()));
										}
										if(type == Tools.LINE) {
											addGraphic(new Line(sx,sy,x,y,canva,owner,nextID()));
										}
										if(type == Tools.MOVE) {
											graphics.get(moved).modifyCords(relx, rely);
											graphics.get(moved).setLocked(false);
											sendChange(graphics.get(moved), Tools.MOVE.toString());
											moved = 0;
											captured = false;
											locked = false;
											relx = 0;
											rely = 0;
											redraw();
										}
										if(type == Tools.BRUSH) {
											canva.setStrokeStyle("#000000");
											canva.beginPath();
											canva.moveTo(lastx,lasty);
											canva.lineTo(x,y);
											canva.closePath();
											canva.stroke();
											addGraphic(new Brush(new Vector<Integer>(xs),new Vector<Integer>(ys),canva,owner,nextID()));
											captured = false;
											redraw();
										}
										if(type == Tools.UP) {
											int s = graphics.size()-1;
											int i;
											Graphics t1, t2;
											for(i = s; i>=0;--i) {
												if(graphics.get(i).belongsTo(x, y)) {
													break;
												}
											}
											if(i <s && i >=0) {
												t1 = graphics.get(i);
												t2 = graphics.get(i+1);
												sendChange(graphics.get(i), Tools.UP.toString());
												graphics.set(i, t2);
												graphics.set(i+1,t1);												
												redraw();
											}
										}
										if(type == Tools.DOWN) {
											int s = graphics.size()-1;
											int i;
											Graphics t1, t2;
											for(i = s; i>=0;--i) {
												if(graphics.get(i).belongsTo(x, y)) {
													break;
												}
											}
											if(i <=s && i >0) {
												sendChange(graphics.get(i), Tools.DOWN.toString());
												t1 = graphics.get(i);
												t2 = graphics.get(i-1);
												graphics.set(i, t2);
												graphics.set(i-1,t1);
												redraw();
											}
										}
										if(type == Tools.DEL) {
											int s = graphics.size()-1;
											int i;
											for(i = s; i>=0;--i) {
												if(graphics.get(i).belongsTo(x, y)) {
													break;
												}
											}
											if(i>=0) {
												sendChange(graphics.get(i), Tools.DEL.toString());
												graphics.remove(i);
												redraw();
											}
										}
										down = false;
										nx = ny = 0;
										lastx = x;
										lasty = y;
									}
									
		});

		initWidget(whiteboardPanel);
	}
	
	/**
	 * Pobiera układ graficzny tablicy.
	 * @return	Panel z ułożonymi elementami graficznymi tablicy.
	 */
	public Widget getLayout() {
		return whiteboardPanel;
	}
	
	/**
	 * Wysyłanie zmiany, która nastąpiła na tablicy.
	 * @param g	Obiekt graficzny, który uległ zmiane (został stworzony)
	 */
	public void sendChange(Graphics g, String tool) {
		conf.send(new WhiteboardChange(conf.getConferenceId(),g, Tools.valueOf((tool))));
	}
	/**
	 * Dodawanie obiektu graficznego do listy obiektów.
	 * @param g
	 */
	public void addGraphic(Graphics g) {
		sendChange(g, Tools.NEW.toString());
		String t = g.getName();
		if(t!=null) {
			if(t.compareTo("Image") == 0) {
				((Image)g).setCreate(false);
			}
		}
		graphics.add(g);
	}
	
	/**
	 * Przerysowanie wszystkich obiektów graficznych na płótnie.
	 */
	public void redraw() {
		canva.clear();
		for(int i = 0; i < graphics.size(); ++i){
			if(!graphics.get(i).isLocked()){
				graphics.get(i).draw();
			}
		}
	}
	
	/**
	 * Obsługa zdarzenia zmiany na tablicy.
	 * @param change	Zmiana, która nastąpiła.
	 */
	public void handlewhiteboardChange(WhiteboardChange change) {
		// odebrano obiekt graficzny, trzeba wyświetlić:
		Graphics obj = (Graphics)change.getChangedObject();
		int i = 0;
		if(obj != null) {
			obj.setCanva(canva);
			Tools t = change.getTool();
			if(t == Tools.NEW) {
				String name = obj.getName();
				if(name.compareTo("Image") == 0){
					GWT.log("Dodaje obraz !", null);
					((Image)obj).setCreate(false);
				}
				graphics.add(obj);
			}
			else {
				for(i = 0; i < graphics.size(); ++i) {
					if(obj.getOwner().compareTo(graphics.get(i).getOwner()) == 0 && obj.getID().compareTo(graphics.get(i).getID()) == 0) {
						if(obj.getName().compareTo("Locked") == 0){
							GWT.log("*** Znalazlem",null);
							graphics.get(i).setLocked(true);
						}
						if(change.getTool() == Tools.MOVE || change.getTool() == Tools.UP || change.getTool() == Tools.DOWN || change.getTool() == Tools.DEL) {
							if(t == Tools.MOVE) {
								if(obj.getName().compareTo("Image") == 0) {
									Image fresh = (Image)obj;
									Image old = (Image)graphics.get(i);
									fresh.setImage(old.getImage());
									fresh.setCreate(false);
									graphics.set(i, fresh);
								}
								else{
									graphics.set(i, obj);
								}
							}
							else if(t == Tools.UP) {
								int s = graphics.size()-1;
								Graphics t1, t2;
								if(i <s && i >=0) {
									t1 = graphics.get(i);
									t2 = graphics.get(i+1);
									graphics.set(i, t2);
									graphics.set(i+1,t1);												
									redraw();
								}
							}
							else if(t == Tools.DOWN) {
								int s = graphics.size()-1;
								Graphics t1, t2;
								if(i <=s && i >0) {
									t1 = graphics.get(i);
									t2 = graphics.get(i-1);
									graphics.set(i, t2);
									graphics.set(i-1,t1);
									redraw();
								}
							}
							else if(t == Tools.DEL) {
								int s = graphics.size();
								if(i>=0 && i< s) {
									graphics.remove(i);
									redraw();
								}
							}
						}
						break;
					}
				}
			}
		}
		else if(change.getTool() == Tools.CLR){
			graphics.clear();
		}
		this.redraw();
	}
	
	/**
	 * Pobieranie płótna.
	 * @return	Płótno.
	 */
	public Canvas getCanva() {
		return this.canva;
	}
	/**
	 * Ustawianie właściciela.
	 * @param o	Nazwa właściciela.
	 */
	public void setOwner(String o) {
		owner = o;
	}
	/**
	 * Tworzenie kolejnego identyfikatora obiektu.
	 * @return	Kolejny identyfikator obiektu.
	 */
	private String nextID() {
		++objID;
		return Integer.toString(objID);
	}
	
	/**
	 * Synchronizacja tablicy z nowym członkiem konferencji.
	 * @param newMember	Nazwa nowego członka konferencji.
	 */
	public void syncWith(String newMember) {
		for(int i = 0; i < graphics.size(); ++i) {
			conf.sendTo(newMember, new WhiteboardChange(conf.getConferenceId(),graphics.get(i), Tools.NEW));
		}
	}
}